package instance

import (
	"crypto/md5"
	"encoding/hex"
	"encoding/json"
	"time"

	"gitee.com/shiwjlinux/arm/apps/game"
)

// curl http://127.0.0.1:8080/api/v1/instances

type PortMapping struct {
	HostPort      int    `json:"HostPort"`
	ContainerPort int    `json:"ContainerPort"`
	Protocol      string `json:"Protocol"`
	HostIP        string `json:"HostIP"`
}

func (p *PortMapping) String() string {
	b, _ := json.MarshalIndent(p, " ", " ")
	return string(b)
}

type Mount struct {
	Destination string    `json:"destination"`
	Type        string    `json:"type"`
	Source      string    `json:"source"`
	Options     []*string `json:"options"`
}

func (m *Mount) String() string {
	b, _ := json.MarshalIndent(m, " ", " ")
	return string(b)
}

func NewMount() *Mount {
	return &Mount{
		Options: make([]*string, 0),
	}
}

type Environment struct {
	Key   string `json:"key"`
	Value string `json:"value"`
}

func (e *Environment) String() string {
	b, _ := json.MarshalIndent(e, " ", " ")
	return string(b)
}

func NewEnvironment() *Environment {
	return &Environment{}
}

type CreateInstanceRequest struct {
	Command      string         `json:"Command" bson:"Command"`
	CreatedAt    string         `json:"CreatedAt" bson:"CreatedAt"`
	ID           string         `json:"ID" bson:"_id"` // 镜像ID
	Image        string         `json:"Image" bson:"Image"`
	Platform     string         `json:"Platform" bson:"Platform"`
	Names        string         `json:"Names" bson:"Names"`
	Ports        string         `json:"Ports" bson:"Ports"`
	PortMappings []*PortMapping `json:"PortMappings" bson:"PortMappings"`
	Status       string         `json:"Status" bson:"Status"`
	Pid          int            `json:"Pid" bson:"Pid"`
	Index        int            `json:"Index" bson:"Index"`
	NetworkMode  string         `json:"NetworkMode" bson:"NetworkMode"`
	Mounts       []*Mount       `json:"Mounts" bson:"Mount"`
	Environments []string       `json:"Environments" bson:"Environments"`
	// Games        []*game.Game   `json:"games" bson:"games"`
}

func (c *CreateInstanceRequest) String() string {
	b, _ := json.MarshalIndent(c, " ", " ")
	return string(b)
}

type Meta struct {
	Hostname        string `json:"hostname" bson:"hostname"` // 主机名
	Sn              string `json:"sn" bson:"sn"`             // 板卡SN
	ServerUpdatedAt int64  `json:"server_updated_at" bson:"server_updated_at"`
}

// 心跳 ，时间戳
type Heartbeat struct {
	UpdatedAt int64 `json:"updated_at" bson:"updated_at"`
	// ServerUpdatedAt int64 `json:"server_updated_at" bson:"server_updated_at"`
}

func NewHeartbeat() *Heartbeat {
	return &Heartbeat{
		// UpdatedAt 由客户端上报
		UpdatedAt: time.Now().Unix(),
	}
}

func NewCreateInstanceRequest() *CreateInstanceRequest {
	return &CreateInstanceRequest{
		PortMappings: make([]*PortMapping, 0, 5),
		Mounts:       []*Mount{NewMount()},
		Environments: []string{},
		// Tags:         make(map[string]string),
		// Games: []*game.Game{},
	}
}

type Instance struct {
	// Tags map[string]string `json:"tags" bson:"tags"`
	*Meta                  `bson:"inline"`
	*CreateInstanceRequest `bson:"inline"`
	*Heartbeat             `bson:"inline"`
	*game.GameSet          `bson:"inline"`
}

func NewInstance() *Instance {
	return &Instance{
		Meta:                  &Meta{ServerUpdatedAt: time.Now().Unix()}, // 有请求过来，服务器生成时间，避免client时间不准
		CreateInstanceRequest: NewCreateInstanceRequest(),
		Heartbeat:             NewHeartbeat(),
		GameSet:               game.NewGameSet(),
	}
}

func (i *Instance) FromRequest(r *CreateInstanceRequest) *Instance {
	i.CreateInstanceRequest = r
	return i
}

func (i *Instance) WithSn(sn string) *Instance {
	i.Sn = sn
	return i
}

func (i *Instance) WithID(id string) *Instance {
	i.ID = id
	return i
}

func (i *Instance) WithHostname(hostname string) *Instance {
	i.Hostname = hostname
	return i
}

func (i *Instance) WithUpdatedAt(updated_at int64) *Instance {
	i.UpdatedAt = updated_at
	return i
}

func (i *Instance) WithGameSet(gameSet *game.GameSet) *Instance {
	i.GameSet = gameSet
	return i
}

// func DefaultInstance() *Instance {
// 	return &Instance{
// 		CreateInstanceRequest: NewCreateInstanceRequest(),
// 	}
// }

// Instance 添加 Hash 方法
func (i *Instance) Hash() string {
	if i == nil {
		return ""
	}
	// 客户端服务器做比较时，要忽略的字段
	i.UpdatedAt = 0
	i.ServerUpdatedAt = 0
	// i.GameSet = nil

	// fmt.Println(i)
	h := md5.New()
	b, _ := json.Marshal(i)
	h.Write(b)
	hs := hex.EncodeToString(h.Sum(nil))
	// fmt.Printf("hash string %s,%s\n", i.Names, hs)
	return hs
}

func (i *Instance) String() string {
	b, _ := json.MarshalIndent(i, " ", " ")
	return string(b)
}

type InstanceSet struct {
	Items []*Instance `json:"items"`
	Total int64       `json:"total"`
}

func (i *InstanceSet) String() string {
	b, _ := json.MarshalIndent(i, " ", " ")
	return string(b)
}

func NewInstanceSet() *InstanceSet {
	return &InstanceSet{
		Items: make([]*Instance, 0, 10),
	}
}
